package api

import (
	"context"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"time"

	"dev.ixmxm.top/rms/boot"
	"dev.ixmxm.top/rms/codes"
	"dev.ixmxm.top/rms/managers/robotmanager"
	"dev.ixmxm.top/rms/model"
	"dev.ixmxm.top/rms/utils/log"
	"github.com/gin-gonic/gin"
	"github.com/tealeg/xlsx"
)

// @Summary 添加机器人类型
// @Description
// @Accept application/json
// @Produce application/json
// @Param body body model.RobotType true "机器人类型"
// @Success 0 {object} ResponseExample "返回数据格式"
// @Tags 机器人
// @Router /robot/add_robot_type [post]
func (hg *HttpGateway) AddRobotType(ctx context.Context, params interface{}) (interface{}, codes.Code) {
	p := params.(*addRobotTypeParams)
	robotType, _ := robotmanager.GetTypeFromDB(ctx, p.CategoryId)
	if robotType != nil {
		return nil, codes.ErrRobotTypeExists
	}
	p.RobotType.SetRobotTypeParams()
	//下发配置到小车
	defer hg.dispatcher.SendConfigToRobots(ctx, &p.RobotType)
	//保存数据库和缓存
	return nil, robotmanager.AddType(ctx, &p.RobotType)
}

// @Summary 机器人类型删除操作
// @Description
// @Accept application/json
// @Produce application/json
// @Param category_id query int true "机器人类型ID"
// @Success 0 {object} ResponseExample "返回数据格式"
// @Tags 机器人
// @Router /robot/delete_robot_type [delete]
func (hg *HttpGateway) DeleteRobotType(ctx context.Context, params interface{}) (interface{}, codes.Code) {
	p := params.(*RobotTypeDeleteParams)
	robots, err := robotmanager.GetAllAccountFromDB(ctx)
	if err != nil {
		log.ErrorfWithContext(ctx, "get robot types error:%s", err.UnWrapError())
		return nil, err
	}
	for _, robot := range robots {
		if robot.CategoryID == p.CategoryID {
			return nil, codes.ErrRobotTypeExists.WithDetails("机器人类型使用中，不可删除")
		}
	}
	return nil, robotmanager.DeleteTypeFromDB(ctx, p.CategoryID)
}

// @Summary 修改机器人类型接口现实
// @Description
// @Accept application/json
// @Produce application/json
// @Param category_id query int true "机器人类型ID"
// @Param body body model.RobotType true "机器人类型"
// @Success 0 {object} ResponseExample "返回数据格式"
// @Tags 机器人
// @Router /robot/save_robot_type [post]
func (hg *HttpGateway) SaveRobotType(ctx context.Context, params interface{}) (interface{}, codes.Code) {
	p := params.(*saveRobotTypeParams)
	txctx := boot.Begin(ctx)
	robotType, _ := robotmanager.GetTypeFromDB(txctx, p.CID)
	if robotType == nil {
		txctx.Rollback()
		return nil, codes.ErrRobotTypeNotExist
	}
	// err := hg.dispatcher.RM().DeleteTypeFromDB(txctx, p.CID)
	// if err != nil {
	// 	txctx.Rollback()
	// 	return nil, err
	// }
	p.RobotType.SetRobotTypeParams()
	err := robotmanager.AddType(txctx, &p.RobotType)
	if err != nil {
		txctx.Rollback()
		return nil, err
	}
	txctx.Commit()
	//下发配置到小车
	hg.dispatcher.SendConfigToRobots(ctx, &p.RobotType)
	//写入缓存和数据库
	return nil, nil
}

// @Summary 获取所有机器人类型信息
// @Description
// @Accept application/json
// @Produce application/json
// @Success 0 {object} ResponseExampleList "返回数据格式"
// @Success 1 {object} []model.RobotType "data数据：机器人类型集合"
// @Tags 机器人
// @Router /robot/get_robot_types [get]
func (hg *HttpGateway) GetRobotTypes(ctx context.Context, params interface{}) (interface{}, codes.Code) {
	types, err := robotmanager.GetAllTypesFromDB(ctx)
	if err != nil {
		log.ErrorfWithContext(ctx, "get robot types error:%s", err.UnWrapError())
		return nil, err
	}
	return types, nil
}

// @Summary 上传AGV类型文件(Excel文件)
// @Description
// @Param excel formData file true "Excel文件"
// @Produce  json
// @Success 0 {object} ResponseExample "返回数据格式"
// @Tags 机器人
// @Router /robot/upload_excel_robot_types [post]
func (hg *HttpGateway) UploadExcelRobotTypes(ctx context.Context, c *gin.Context) (interface{}, codes.Code) {
	//先读取Excel 文件
	file, _, err := c.Request.FormFile("excel")
	if file == nil {
		return nil, codes.ErrDoHttpRequest.WithDetails("Excel文件传入有误，未找到XML").Wrap(err)
	}
	excelBytes, err := ioutil.ReadAll(file)
	if excelBytes == nil {
		return nil, codes.ErrDoHttpRequest.WithDetails("Excel文件传入有误，读取失败").Wrap(err)
	}
	xlFile, err := xlsx.OpenBinary(excelBytes)
	if err != nil {
		return nil, codes.ErrDoHttpRequest.WithDetails("Excel文件传入有误，读取失败").Wrap(err)
	}

	data := ImportExcel(xlFile, 21)
	if data == nil {
		return nil, codes.ErrDoHttpRequest.WithDetails("Excel文件传入有误,数据内容有误，读取失败")
	}
	//将所有的集合数据转换成对象集合
	var RobotTypesArr []interface{}
	// var RobotTypesArr []model.RobotType
	for i := 0; i < len(data); i++ {
		var row = data[i]
		//初始化实体类
		var robotType_1 model.RobotType
		categoryId, err1 := strconv.Atoi(row[0])
		categoryType, err2 := strconv.Atoi(row[1])
		categoryName := row[2]
		length, err3 := strconv.Atoi(row[3])
		lengthToFront, err4 := strconv.Atoi(row[4])
		width, err5 := strconv.Atoi(row[5])
		// rotateRadius, err5 := strconv.Atoi(row[5])
		// rotateBackRadius, err6 := strconv.Atoi(row[6])
		safeDis, err6 := strconv.Atoi(row[6])
		backSafeDis, err7 := strconv.Atoi(row[7])
		rotateSafeDis, err8 := strconv.Atoi(row[8])
		sideSafeDis, err9 := strconv.Atoi(row[9])
		maxVel, err10 := strconv.ParseInt(row[10], 10, 64)
		maxAng, err11 := strconv.ParseInt(row[11], 10, 64)
		rotateTime, err12 := strconv.ParseInt(row[12], 10, 64)
		stopTime, err13 := strconv.Atoi(row[13])
		chargePercent, err14 := strconv.Atoi(row[14])
		chargeToTaskPercent, err15 := strconv.Atoi(row[15])
		localPathNodeNum, err16 := strconv.Atoi(row[16])
		localPathDis, err17 := strconv.ParseInt(row[17], 10, 64)
		walkSafeHeight, err18 := strconv.ParseInt(row[18], 10, 32)
		goodsWidth, err19 := strconv.Atoi(row[19])
		goodslength, err20 := strconv.Atoi(row[20])
		if err1 != nil || err2 != nil || err3 != nil || err4 != nil || err5 != nil || err6 != nil || err7 != nil || err8 != nil || err9 != nil || err10 != nil ||
			err11 != nil || err12 != nil || err13 != nil || err14 != nil || err15 != nil || err16 != nil || err17 != nil || err18 != nil || err19 != nil || err20 != nil {
			return nil, codes.ErrDoHttpRequest.WithDetails("Excel文件传入有误,内容存在格式问题，读取失败")
		}
		robotType_1.CategoryId = categoryId
		robotType_1.CategoryType = model.RobotCategoryType(categoryType)
		robotType_1.CategoryName = categoryName
		robotType_1.Length = length
		robotType_1.LengthToFront = lengthToFront
		robotType_1.Width = width
		// robotType_1.RotateRadius = rotateRadius
		// robotType_1.RotateBackRadius = rotateBackRadius
		robotType_1.SafeDis = safeDis
		robotType_1.BackSafeDis = backSafeDis
		robotType_1.RotateSafeDis = rotateSafeDis
		robotType_1.SideSafeDis = sideSafeDis
		robotType_1.MaxVel = maxVel
		robotType_1.MaxAng = maxAng
		robotType_1.RotateTime = rotateTime
		robotType_1.StopTime = stopTime
		robotType_1.ChargePercent = chargePercent
		robotType_1.ChargeToTaskPercent = chargeToTaskPercent
		robotType_1.LocalPathNodeNum = localPathNodeNum
		robotType_1.LocalPathDis = localPathDis
		robotType_1.WalkSafeHeight = int32(walkSafeHeight)
		robotType_1.GoodsWidth = goodsWidth
		robotType_1.Goodslength = goodslength
		robotType_1.SetRobotTypeParams()

		//添加入数组
		RobotTypesArr = append(RobotTypesArr, robotType_1)
	}
	//调用接口处理导入数据
	err1 := robotmanager.ImportAllRobtType(ctx, RobotTypesArr)
	if err1 != nil {
		return nil, codes.ErrDoHttpRequest.WithDetails("Excel文件传入有误，读取失败").Wrap(err1)
	}
	return nil, nil
}

// @Summary 下载所有AGV类型(excel文件)
// @Description
// @Accept application/json
// @Produce application/json
// @Success 0 {object} ResponseExample "返回数据格式"
// @Tags 机器人
// @Router /robot/download_excel_robot_types [get]
func (hg *HttpGateway) DownloadExcelRobotTypes(ctx context.Context, params interface{}, c *gin.Context) (interface{}, codes.Code) {
	robotTypes, err := robotmanager.GetAllTypesFromDB(ctx)
	if err != nil {
		log.ErrorfWithContext(ctx, "get all maps error:%s", err.UnWrapError())
		return nil, err
	}
	type DownLoadRobotType struct {
		CategoryId          int
		CategoryTypeValue   int
		CategoryName        string
		Length              int
		LengthToFront       int
		Width               int
		SafeDis             int
		BackSafeDis         int
		RotateSafeDis       int
		SideSafeDis         int
		MaxVel              int64
		MaxAng              int64
		RotateTime          int64
		StopTime            int
		ChargePercent       int
		ChargeToTaskPercent int
		LocalPathNodeNum    int
		LocalPathDis        int64
		WalkSafeHeight      int32
		GoodsWidth          int
		Goodslength         int
	}
	var res []interface{}
	for _, robotType := range robotTypes {
		categoryTypeValue := int(robotType.CategoryType)
		res = append(res, &DownLoadRobotType{
			CategoryId:          robotType.CategoryId,
			CategoryTypeValue:   categoryTypeValue,
			CategoryName:        robotType.CategoryName,
			Length:              robotType.Length,
			LengthToFront:       robotType.LengthToFront,
			Width:               robotType.Width,
			SafeDis:             robotType.SafeDis,
			BackSafeDis:         robotType.BackSafeDis,
			RotateSafeDis:       robotType.RotateSafeDis,
			SideSafeDis:         robotType.SideSafeDis,
			MaxVel:              robotType.MaxVel,
			MaxAng:              robotType.MaxAng,
			RotateTime:          robotType.RotateTime,
			StopTime:            robotType.StopTime,
			ChargePercent:       robotType.ChargePercent,
			ChargeToTaskPercent: robotType.ChargeToTaskPercent,
			LocalPathNodeNum:    robotType.LocalPathNodeNum,
			LocalPathDis:        robotType.LocalPathDis,
			WalkSafeHeight:      robotType.WalkSafeHeight,
			GoodsWidth:          robotType.GoodsWidth,
			Goodslength:         robotType.Goodslength,
		})
	}
	fileName := fmt.Sprintf("%s%s%s.xlsx", "AGV类型", ":", time.Now())
	// c.Writer.Header().Add("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, fileName))
	c.Writer.Header().Add("Content-Disposition", fmt.Sprintf("attachment; filename*=UTF-8''%s", url.QueryEscape(fileName)))
	c.Writer.Header().Add("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
	content := ToExcel([]string{"编号", "主类型编码", "别名", "长度", "头部长度", "宽度", "车头安全距离", "车尾安全距离", "旋转安全距离", "侧向安全距离", "直线速度", "弧线速度", "旋转耗时", "停车耗时", "充电阈值", "任务断电阈值", "路径数", "路径长度", "安全高度", "载货车体宽度", "载货车体长度"}, res)
	http.ServeContent(c.Writer, c.Request, fileName, time.Now(), content)
	// c.Data(200, "application/octet-stream", content)
	return nil, nil
}
